
/**
  ******************************************************************************
  * Copyright 2021 The grapilot Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       param.h
  * @author     baiyang
  * @date       2021-7-12
  ******************************************************************************
  */

#pragma once

#ifdef __cplusplus
extern "C"{
#endif

/*----------------------------------include-----------------------------------*/
#include <stdint.h>
#include <common/gp_config.h>
/*-----------------------------------macro------------------------------------*/
#define PARAM_MAX_NAME_SIZE    16

#define PARAM_DECLARE(_name) param_t _name

#define PARAM_DEFINE_INT8(_name, _default) \
    {                                      \
        .name = #_name,                    \
        .type = PARAM_TYPE_INT8,           \
        .val.i8 = _default                 \
    }

#define PARAM_DEFINE_UINT8(_name, _default) \
    {                                       \
        .name = #_name,                     \
        .type = PARAM_TYPE_UINT8,           \
        .val.u8 = _default                  \
    }

#define PARAM_DEFINE_INT16(_name, _default) \
    {                                       \
        .name = #_name,                     \
        .type = PARAM_TYPE_INT16,           \
        .val.i16 = _default                 \
    }

#define PARAM_DEFINE_UINT16(_name, _default) \
    {                                        \
        .name = #_name,                      \
        .type = PARAM_TYPE_UINT16,           \
        .val.u16 = _default                  \
    }

#define PARAM_DEFINE_INT32(_name, _default) \
    {                                       \
        .name = #_name,                     \
        .type = PARAM_TYPE_INT32,           \
        .val.i32 = _default                 \
    }

#define PARAM_DEFINE_UINT32(_name, _default) \
    {                                        \
        .name = #_name,                      \
        .type = PARAM_TYPE_UINT32,           \
        .val.u32 = _default                  \
    }

#define PARAM_DEFINE_FLOAT(_name, _default) \
    {                                       \
        .name = #_name,                     \
        .type = PARAM_TYPE_FLOAT,           \
        .val.f = _default                   \
    }

#define PARAM_DEFINE_DOUBLE(_name, _default) \
    {                                        \
        .name = #_name,                      \
        .type = PARAM_TYPE_DOUBLE,           \
        .val.lf = _default                   \
    }

#define PARAM_GROUP(_group)         _param_##_group
#define PARAM_DECLARE_GROUP(_group) _param_##_group##_t
#define PARAM_DEFINE_GROUP(_group)                                  \
    {                                                               \
        .name = #_group,                                            \
        .param_num = sizeof(_param_##_group##_t) / sizeof(param_t), \
        .content = (param_t*)&_param_##_group##_t                   \
    }

#define PARAM_GET(_group, _name) ((_param_##_group*)(param_list._param_##_group.content))->_name

#define PARAM_GET_INT8(_group, _name)   ((_param_##_group*)(param_list._param_##_group.content))->_name.val.i8
#define PARAM_GET_UINT8(_group, _name)  ((_param_##_group*)(param_list._param_##_group.content))->_name.val.u8
#define PARAM_GET_INT16(_group, _name)  ((_param_##_group*)(param_list._param_##_group.content))->_name.val.i16
#define PARAM_GET_UINT16(_group, _name) ((_param_##_group*)(param_list._param_##_group.content))->_name.val.u16
#define PARAM_GET_INT32(_group, _name)  ((_param_##_group*)(param_list._param_##_group.content))->_name.val.i32
#define PARAM_GET_UINT32(_group, _name) ((_param_##_group*)(param_list._param_##_group.content))->_name.val.u32
#define PARAM_GET_FLOAT(_group, _name)  ((_param_##_group*)(param_list._param_##_group.content))->_name.val.f
#define PARAM_GET_DOUBLE(_group, _name) ((_param_##_group*)(param_list._param_##_group.content))->_name.val.lf

#define PARAM_SET_INT8(_group, _name, _val)   ((_param_##_group*)(param_list._param_##_group.content))->_name.val.i8 = _val
#define PARAM_SET_UINT8(_group, _name, _val)  ((_param_##_group*)(param_list._param_##_group.content))->_name.val.u8 = _val
#define PARAM_SET_INT16(_group, _name, _val)  ((_param_##_group*)(param_list._param_##_group.content))->_name.val.i16 = _val
#define PARAM_SET_UINT16(_group, _name, _val) ((_param_##_group*)(param_list._param_##_group.content))->_name.val.u16 = _val
#define PARAM_SET_INT32(_group, _name, _val)  ((_param_##_group*)(param_list._param_##_group.content))->_name.val.i32 = _val
#define PARAM_SET_UINT32(_group, _name, _val) ((_param_##_group*)(param_list._param_##_group.content))->_name.val.u32 = _val
#define PARAM_SET_FLOAT(_group, _name, _val)  ((_param_##_group*)(param_list._param_##_group.content))->_name.val.f = _val
#define PARAM_SET_DOUBLE(_group, _name, _val) ((_param_##_group*)(param_list._param_##_group.content))->_name.val.lf = _val

/*----------------------------------typedef-----------------------------------*/
/*定义参数/组包括4个步骤
     *步骤1：声明组
     *步骤2：在组中声明参数
     *步骤3：定义组
     *步骤4：在组中定义参数
*/

enum param_type_t {
    PARAM_TYPE_INT8 = 0,
    PARAM_TYPE_UINT8,
    PARAM_TYPE_INT16,
    PARAM_TYPE_UINT16,
    PARAM_TYPE_INT32,
    PARAM_TYPE_UINT32,
    PARAM_TYPE_FLOAT,
    PARAM_TYPE_DOUBLE,
    PARAM_TYPE_UNKNOWN = 0xFF
};

typedef enum {
    PARAM_PARSE_START = 0,
    PARAM_PARSE_LIST,
    PARAM_PARSE_GROUP_INFO,
    PARAM_PARSE_GROUP_NAME,
    PARAM_PARSE_GROUP,
    PARAM_PARSE_PARAM,
    PARAM_PARSE_PARAM_NAME,
    PARAM_PARSE_PARAM_VAL,
    PARAM_PARSE_PARAM_VAL_CONTENT,
} PARAM_PARSE_STATE;

typedef union {
    int8_t i8;
    uint8_t u8;
    int16_t i16;
    uint16_t u16;
    int32_t i32;
    uint32_t u32;
    float f;
    double lf;
} param_value_t;

typedef struct {
    const char* name;
    const uint8_t type;
    param_value_t val;
} param_t;

typedef struct {
    const char* name;
    const uint32_t param_num;
    param_t* content;
} param_group_t;

/*---------------------------------步骤二：在组中声明参数-------------------------------*/
typedef struct
{
    PARAM_DECLARE(PSC_POSZ_P);
    
    PARAM_DECLARE(PSC_VELZ_P);
    PARAM_DECLARE(PSC_VELZ_I);
    PARAM_DECLARE(PSC_VELZ_D);
    PARAM_DECLARE(PSC_VELZ_IMAX);
    PARAM_DECLARE(PSC_VELZ_FF);
    PARAM_DECLARE(PSC_VELZ_FLTD);
    PARAM_DECLARE(PSC_VELZ_FLTE);
    
    PARAM_DECLARE(PSC_ACCZ_P);
    PARAM_DECLARE(PSC_ACCZ_I);
    PARAM_DECLARE(PSC_ACCZ_D);
    PARAM_DECLARE(PSC_ACCZ_IMAX);
    PARAM_DECLARE(PSC_ACCZ_FF);
    PARAM_DECLARE(PSC_ACCZ_FLTD);
    PARAM_DECLARE(PSC_ACCZ_FLTE);
    PARAM_DECLARE(PSC_ACCZ_FLTT);
    PARAM_DECLARE(PSC_ACCZ_SMAX);
    
    PARAM_DECLARE(PSC_POSXY_P);
    
    PARAM_DECLARE(PSC_VELXY_P);
    PARAM_DECLARE(PSC_VELXY_I);
    PARAM_DECLARE(PSC_VELXY_D);
    PARAM_DECLARE(PSC_VELXY_IMAX);
    PARAM_DECLARE(PSC_VELXY_FF);
    PARAM_DECLARE(PSC_VELXY_FLTD);
    PARAM_DECLARE(PSC_VELXY_FLTE);

    PARAM_DECLARE(PSC_ANGLE_MAX);
    PARAM_DECLARE(PSC_JERK_XY);
    PARAM_DECLARE(PSC_JERK_Z);

}PARAM_GROUP(POS_CTRL);

typedef struct
{
    PARAM_DECLARE(GYR_X_OFFSET);
    PARAM_DECLARE(GYR_Y_OFFSET);
    PARAM_DECLARE(GYR_Z_OFFSET);
    PARAM_DECLARE(GYR_X_GAIN);
    PARAM_DECLARE(GYR_Y_GAIN);
    PARAM_DECLARE(GYR_Z_GAIN);
    PARAM_DECLARE(GYR_CALIB);
    PARAM_DECLARE(ACC_X_OFFSET);
    PARAM_DECLARE(ACC_Y_OFFSET);
    PARAM_DECLARE(ACC_Z_OFFSET);
    PARAM_DECLARE(ACC_TRANS_MAT00);
    PARAM_DECLARE(ACC_TRANS_MAT01);
    PARAM_DECLARE(ACC_TRANS_MAT02);
    PARAM_DECLARE(ACC_TRANS_MAT10);
    PARAM_DECLARE(ACC_TRANS_MAT11);
    PARAM_DECLARE(ACC_TRANS_MAT12);
    PARAM_DECLARE(ACC_TRANS_MAT20);
    PARAM_DECLARE(ACC_TRANS_MAT21);
    PARAM_DECLARE(ACC_TRANS_MAT22);
    PARAM_DECLARE(ACC_CALIB);
    PARAM_DECLARE(MAG_X_OFFSET);
    PARAM_DECLARE(MAG_Y_OFFSET);
    PARAM_DECLARE(MAG_Z_OFFSET);
    PARAM_DECLARE(MAG_TRANS_MAT00);
    PARAM_DECLARE(MAG_TRANS_MAT01);
    PARAM_DECLARE(MAG_TRANS_MAT02);
    PARAM_DECLARE(MAG_TRANS_MAT10);
    PARAM_DECLARE(MAG_TRANS_MAT11);
    PARAM_DECLARE(MAG_TRANS_MAT12);
    PARAM_DECLARE(MAG_TRANS_MAT20);
    PARAM_DECLARE(MAG_TRANS_MAT21);
    PARAM_DECLARE(MAG_TRANS_MAT22);
    PARAM_DECLARE(MAG_CALIB);
    PARAM_DECLARE(LEVEL_XOFF);
    PARAM_DECLARE(LEVEL_YOFF);
    PARAM_DECLARE(LEVEL_ZOFF);
}PARAM_GROUP(CALIBRATION);

typedef struct
{
    PARAM_DECLARE(ATC_SLEW_YAW);
    PARAM_DECLARE(ATC_ANG_RLL_P);
    PARAM_DECLARE(ATC_RAT_RLL_P);
    PARAM_DECLARE(ATC_RAT_RLL_I);
    PARAM_DECLARE(ATC_RAT_RLL_D);
    PARAM_DECLARE(ATC_RAT_RLL_IMAX);
    PARAM_DECLARE(ATC_RAT_RLL_FLTT);
    PARAM_DECLARE(ATC_RAT_RLL_FLTE);
    PARAM_DECLARE(ATC_RAT_RLL_FLTD);
    PARAM_DECLARE(ATC_ANG_PIT_P);
    PARAM_DECLARE(ATC_RAT_PIT_P);
    PARAM_DECLARE(ATC_RAT_PIT_I);
    PARAM_DECLARE(ATC_RAT_PIT_D);
    PARAM_DECLARE(ATC_RAT_PIT_IMAX);
    PARAM_DECLARE(ATC_RAT_PIT_FLTT);
    PARAM_DECLARE(ATC_RAT_PIT_FLTE);
    PARAM_DECLARE(ATC_RAT_PIT_FLTD);
    PARAM_DECLARE(ATC_ANG_YAW_P);
    PARAM_DECLARE(ATC_RAT_YAW_P);
    PARAM_DECLARE(ATC_RAT_YAW_I);
    PARAM_DECLARE(ATC_RAT_YAW_D);
    PARAM_DECLARE(ATC_RAT_YAW_IMAX);
    PARAM_DECLARE(ATC_RAT_YAW_FLTT);
    PARAM_DECLARE(ATC_RAT_YAW_FLTE);
    PARAM_DECLARE(ATC_RAT_YAW_FLTD);
    PARAM_DECLARE(ATC_THR_MIX_MIN);
    PARAM_DECLARE(ATC_THR_MIX_MAN);
    PARAM_DECLARE(ATC_THR_MIX_MAX);
    PARAM_DECLARE(ATC_ACCEL_R_MAX);
    PARAM_DECLARE(ATC_ACCEL_P_MAX);
    PARAM_DECLARE(ATC_ACCEL_Y_MAX);
    PARAM_DECLARE(ATC_RATE_R_MAX);
    PARAM_DECLARE(ATC_RATE_P_MAX);
    PARAM_DECLARE(ATC_RATE_Y_MAX);
    PARAM_DECLARE(ATC_RATE_FF_EN);
    PARAM_DECLARE(ATC_ANGLE_BOOST);
    PARAM_DECLARE(ATC_INPUT_TC);
    PARAM_DECLARE(ATC_ANG_LIM_TC);
}PARAM_GROUP(ATT_CTRL);

typedef struct
{
    PARAM_DECLARE(HIL_SOURCE);
}PARAM_GROUP(HIL_SIM);

typedef struct {
    PARAM_DECLARE(BLOG_MODE);
    PARAM_DECLARE(ANGLE_MAX);
    PARAM_DECLARE(FRAME_CLASS);
    PARAM_DECLARE(FRAME_TYPE);
    PARAM_DECLARE(FS_THR_ENABLE);
    PARAM_DECLARE(FS_THR_VALUE);
    PARAM_DECLARE(THR_DZ);
    PARAM_DECLARE(BLOG_IMU_SPEED);
    PARAM_DECLARE(PILOT_THR_FILT);
    PARAM_DECLARE(ACRO_YAW_P);
    PARAM_DECLARE(ACRO_Y_EXPO);
    PARAM_DECLARE(PILOT_THR_BHV);
    PARAM_DECLARE(DISARM_DELAY);
    PARAM_DECLARE(PILOT_SPEED_UP);
    PARAM_DECLARE(PILOT_SPEED_DN);
    PARAM_DECLARE(PILOT_ACCEL_Z);
    PARAM_DECLARE(PILOT_TKOFF_ALT);
} PARAM_GROUP(VEHICLE);

typedef struct {
    PARAM_DECLARE(WPNAV_SPEED);
    PARAM_DECLARE(WPNAV_RADIUS);
    PARAM_DECLARE(WPNAV_SPEED_UP);
    PARAM_DECLARE(WPNAV_SPEED_D);
    PARAM_DECLARE(WPNAV_ACC_XY);
    PARAM_DECLARE(WPNAV_ACC_Z);
    PARAM_DECLARE(WPNAV_RFND_USE);
    PARAM_DECLARE(WPNAV_ALT_MIN);
    PARAM_DECLARE(WPNAV_LAND_SPEED);
    PARAM_DECLARE(WPNAV_LAND_ALT);
} PARAM_GROUP(WPNAV);

typedef struct {
    PARAM_DECLARE(LOITER_ANG_MAX);
    PARAM_DECLARE(LOITER_SPEED);
    PARAM_DECLARE(LOITER_ACC_MAX);
    PARAM_DECLARE(LOITER_BK_ACC);
    PARAM_DECLARE(LOITER_BK_JERK);
    PARAM_DECLARE(LOITER_BK_DELAY);
} PARAM_GROUP(LOITER);

typedef struct {
    PARAM_DECLARE(RC_MAX);
    PARAM_DECLARE(RC_MIN);
    PARAM_DECLARE(RC_MID);
    PARAM_DECLARE(RCMAP_ROLL);
    PARAM_DECLARE(RCMAP_PITCH);
    PARAM_DECLARE(RCMAP_YAW);
    PARAM_DECLARE(RCMAP_THROTTLE);
    PARAM_DECLARE(RC1_MIN);
    PARAM_DECLARE(RC1_MAX);
    PARAM_DECLARE(RC1_TRIM);
    PARAM_DECLARE(RC1_DZ);
    PARAM_DECLARE(RC1_OPTION);
    PARAM_DECLARE(RC2_MIN);
    PARAM_DECLARE(RC2_MAX);
    PARAM_DECLARE(RC2_TRIM);
    PARAM_DECLARE(RC2_DZ);
    PARAM_DECLARE(RC2_OPTION);
    PARAM_DECLARE(RC3_MIN);
    PARAM_DECLARE(RC3_MAX);
    PARAM_DECLARE(RC3_TRIM);
    PARAM_DECLARE(RC3_DZ);
    PARAM_DECLARE(RC3_OPTION);
    PARAM_DECLARE(RC4_MIN);
    PARAM_DECLARE(RC4_MAX);
    PARAM_DECLARE(RC4_TRIM);
    PARAM_DECLARE(RC4_DZ);
    PARAM_DECLARE(RC4_OPTION);
    PARAM_DECLARE(RC5_MIN);
    PARAM_DECLARE(RC5_MAX);
    PARAM_DECLARE(RC5_TRIM);
    PARAM_DECLARE(RC5_DZ);
    PARAM_DECLARE(RC5_OPTION);
    PARAM_DECLARE(RC6_MIN);
    PARAM_DECLARE(RC6_MAX);
    PARAM_DECLARE(RC6_TRIM);
    PARAM_DECLARE(RC6_DZ);
    PARAM_DECLARE(RC6_OPTION);
    PARAM_DECLARE(RC7_MIN);
    PARAM_DECLARE(RC7_MAX);
    PARAM_DECLARE(RC7_TRIM);
    PARAM_DECLARE(RC7_DZ);
    PARAM_DECLARE(RC7_OPTION);
    PARAM_DECLARE(RC8_MIN);
    PARAM_DECLARE(RC8_MAX);
    PARAM_DECLARE(RC8_TRIM);
    PARAM_DECLARE(RC8_DZ);
    PARAM_DECLARE(RC8_OPTION);
} PARAM_GROUP(RC);

typedef struct {
    PARAM_DECLARE(FLTMODE_CH);
    PARAM_DECLARE(FLTMODE1);
    PARAM_DECLARE(FLTMODE2);
    PARAM_DECLARE(FLTMODE3);
    PARAM_DECLARE(FLTMODE4);
    PARAM_DECLARE(FLTMODE5);
    PARAM_DECLARE(FLTMODE6);
} PARAM_GROUP(FLIGHTMODE);

typedef struct {
    PARAM_DECLARE(GPS_HDOP);
} PARAM_GROUP(GPS);

typedef struct {
    PARAM_DECLARE(SERIAL1_PROTOCOL);
    PARAM_DECLARE(SERIAL1_BAUD);
    PARAM_DECLARE(SERIAL2_PROTOCOL);
    PARAM_DECLARE(SERIAL2_BAUD);
    PARAM_DECLARE(SERIAL3_PROTOCOL);
    PARAM_DECLARE(SERIAL3_BAUD);
    PARAM_DECLARE(SERIAL4_PROTOCOL);
    PARAM_DECLARE(SERIAL4_BAUD);
    PARAM_DECLARE(SERIAL5_PROTOCOL);
    PARAM_DECLARE(SERIAL5_BAUD);
    PARAM_DECLARE(SERIAL6_PROTOCOL);
    PARAM_DECLARE(SERIAL6_BAUD);
    PARAM_DECLARE(SERIAL7_PROTOCOL);
    PARAM_DECLARE(SERIAL7_BAUD);
    PARAM_DECLARE(SERIAL8_PROTOCOL);
    PARAM_DECLARE(SERIAL8_BAUD);
} PARAM_GROUP(SERIAL);

typedef struct {
    PARAM_DECLARE(MOT_YAW_HEADROOM);
    PARAM_DECLARE(MOT_THST_EXPO);
    PARAM_DECLARE(MOT_SPIN_MAX);
    PARAM_DECLARE(MOT_BAT_VOLT_MAX);
    PARAM_DECLARE(MOT_BAT_VOLT_MIN);
    PARAM_DECLARE(MOT_BAT_CURR_MAX);
    PARAM_DECLARE(MOT_PWM_TYPE);
    PARAM_DECLARE(MOT_PWM_MIN);
    PARAM_DECLARE(MOT_PWM_MAX);
    PARAM_DECLARE(MOT_SPIN_MIN);
    PARAM_DECLARE(MOT_SPIN_ARM);
    PARAM_DECLARE(MOT_BAT_CURR_TC);
    PARAM_DECLARE(MOT_THST_HOVER);
    PARAM_DECLARE(MOT_HOVER_LEARN);
    PARAM_DECLARE(MOT_SAFE_DISARM);
    PARAM_DECLARE(MOT_YAW_SV_ANGLE);
    PARAM_DECLARE(MOT_SPOOL_TIME);
    PARAM_DECLARE(MOT_BOOST_SCALE);
    PARAM_DECLARE(MOT_BAT_IDX);
    PARAM_DECLARE(MOT_SLEW_UP_TIME);
    PARAM_DECLARE(MOT_SLEW_DN_TIME);
    PARAM_DECLARE(MOT_SAFE_TIME);
} PARAM_GROUP(MOTOR);

typedef struct
{
    PARAM_DECLARE(ARMING_REQUIRE);
    PARAM_DECLARE(ARMING_ACCTHRESH);
    PARAM_DECLARE(ARMING_RUDDER);
    PARAM_DECLARE(ARMING_MIS_ITEMS);
    PARAM_DECLARE(ARMING_CHECK);
}PARAM_GROUP(ARMING);

typedef struct {
    PARAM_DECLARE(BATT_VOL_SCALE);
    PARAM_DECLARE(BATT_CUR_SCALE);   
} PARAM_GROUP(BATTERY);

/*---------------------------------步骤一：声明组-----------------------------*/
typedef struct{
    param_group_t    PARAM_GROUP(CALIBRATION);
    param_group_t    PARAM_GROUP(HIL_SIM);
    param_group_t    PARAM_GROUP(ATT_CTRL);
    param_group_t    PARAM_GROUP(POS_CTRL);
    param_group_t    PARAM_GROUP(VEHICLE);
    param_group_t    PARAM_GROUP(WPNAV);
    param_group_t    PARAM_GROUP(LOITER);
    param_group_t    PARAM_GROUP(RC);
    param_group_t    PARAM_GROUP(FLIGHTMODE);
    param_group_t    PARAM_GROUP(GPS);
    param_group_t    PARAM_GROUP(SERIAL);
    param_group_t    PARAM_GROUP(MOTOR);
    param_group_t    PARAM_GROUP(ARMING);
	param_group_t    PARAM_GROUP(BATTERY);
}param_list_t;

/*----------------------------------variable----------------------------------*/
extern param_list_t param_list;
/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
void param_init(void);
void param_interface_init(void);

void param_save(void);
void param_save_to_file(void);
void param_save_if_needed(void);

void param_load(void);

param_t* param_get_by_index(uint32_t index);
param_t* param_get_by_name(const char* param_name);
param_t* param_get_by_full_name(char* group_name, char* param_name);

int param_set_val(param_t* param, void *val);
int param_get_val(param_t* param, void *val);
int param_set_val_by_full_name(char* group_name, char* param_name, char* val);

uint32_t param_get_count(void);
int param_get_index(const param_t* param);
int param_get_index_by_name(char* param_name);

void param_traverse(void (*param_ops)(param_t* param));
/*------------------------------------test------------------------------------*/

#ifdef __cplusplus
}
#endif



